


<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>torch.quantization.observer &mdash; PyTorch master documentation</title>
  

  
  
  
  
    <link rel="canonical" href="https://pytorch.org/docs/stable/_modules/torch/quantization/observer.html"/>
  

  

  
  
    

  

  <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" />
  <!-- <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.0-beta/dist/katex.min.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/css/jit.css" type="text/css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" type="text/css" />
  <link rel="stylesheet" href="../../../_static/katex-math.css" type="text/css" />
    <link rel="index" title="Index" href="../../../genindex.html" />
    <link rel="search" title="Search" href="../../../search.html" /> 

  
  <script src="../../../_static/js/modernizr.min.js"></script>

  <!-- Preload the theme fonts -->

<link rel="preload" href="../../../_static/fonts/FreightSans/freight-sans-book.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../../../_static/fonts/FreightSans/freight-sans-medium.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../../../_static/fonts/IBMPlexMono/IBMPlexMono-Medium.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../../../_static/fonts/FreightSans/freight-sans-bold.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../../../_static/fonts/FreightSans/freight-sans-medium-italic.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="../../../_static/fonts/IBMPlexMono/IBMPlexMono-SemiBold.woff2" as="font" type="font/woff2" crossorigin="anonymous">

<!-- Preload the katex fonts -->

<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Math-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Main-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Main-Bold.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size1-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size4-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size2-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Size3-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/fonts/KaTeX_Caligraphic-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
</head>

<div class="container-fluid header-holder tutorials-header" id="header-holder">
  <div class="container">
    <div class="header-container">
      <a class="header-logo" href="https://pytorch.org/" aria-label="PyTorch"></a>

      <div class="main-menu">
        <ul>
          <li>
            <a href="https://pytorch.org/get-started">Get Started</a>
          </li>

          <li>
            <div class="ecosystem-dropdown">
              <a id="dropdownMenuButton" data-toggle="ecosystem-dropdown">
                Ecosystem
              </a>
              <div class="ecosystem-dropdown-menu">
                <a class="nav-dropdown-item" href="https://pytorch.org/hub"">
                  <span class=dropdown-title>Models (Beta)</span>
                  <p>Discover, publish, and reuse pre-trained models</p>
                </a>
                <a class="nav-dropdown-item" href="https://pytorch.org/ecosystem">
                  <span class=dropdown-title>Tools & Libraries</span>
                  <p>Explore the ecosystem of tools and libraries</p>
                </a>
              </div>
            </div>
          </li>

          <li>
            <a href="https://pytorch.org/mobile">Mobile</a>
          </li>

          <li>
            <a href="https://pytorch.org/blog/">Blog</a>
          </li>

          <li>
            <a href="https://pytorch.org/tutorials">Tutorials</a>
          </li>

          <li class="active">
            <a href="https://pytorch.org/docs/stable/index.html">Docs</a>
          </li>

          <li>
            <div class="resources-dropdown">
              <a id="resourcesDropdownButton" data-toggle="resources-dropdown">
                Resources
              </a>
              <div class="resources-dropdown-menu">
                <a class="nav-dropdown-item" href="https://pytorch.org/resources"">
                  <span class=dropdown-title>Developer Resources</span>
                  <p>Find resources and get questions answered</p>
                </a>
                <a class="nav-dropdown-item" href="https://pytorch.org/features">
                  <span class=dropdown-title>About</span>
                  <p>Learn about PyTorch’s features and capabilities</p>
                </a>
              </div>
            </div>
          </li>

          <li>
            <a href="https://github.com/pytorch/pytorch">Github</a>
          </li>
        </ul>
      </div>

      <a class="main-menu-open-button" href="#" data-behavior="open-mobile-menu"></a>
    </div>

  </div>
</div>


<body class="pytorch-body">

   

    

    <div class="table-of-contents-link-wrapper">
      <span>Table of Contents</span>
      <a href="#" class="toggle-table-of-contents" data-behavior="toggle-table-of-contents"></a>
    </div>

    <nav data-toggle="wy-nav-shift" class="pytorch-left-menu" id="pytorch-left-menu">
      <div class="pytorch-side-scroll">
        <div class="pytorch-menu pytorch-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          <div class="pytorch-left-menu-search">
            

            
              
              
                <div class="version">
                  master (1.5.0 )
                </div>
              
            

            


  


<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
    <input type="text" name="q" placeholder="Search Docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

            
          </div>

          
<div>
  <a style="color:#F05732" href="https://pytorch.org/docs/stable/_modules/torch/quantization/observer.html">
    You are viewing unstable developer preview docs.
    Click here to view docs for latest stable release.
  </a>
</div>

            
            
              
            
            
              <p class="caption"><span class="caption-text">Notes</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/amp_examples.html">Automatic Mixed Precision examples</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/autograd.html">Autograd mechanics</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/broadcasting.html">Broadcasting semantics</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/cpu_threading_torchscript_inference.html">CPU threading and TorchScript inference</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/cuda.html">CUDA semantics</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/ddp.html">Distributed Data Parallel</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/extending.html">Extending PyTorch</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/faq.html">Frequently Asked Questions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/large_scale_deployments.html">Features for large-scale deployments</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/multiprocessing.html">Multiprocessing best practices</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/randomness.html">Reproducibility</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/serialization.html">Serialization semantics</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../notes/windows.html">Windows FAQ</a></li>
</ul>
<p class="caption"><span class="caption-text">Language Bindings</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="https://pytorch.org/cppdocs/">C++ API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../packages.html">Javadoc</a></li>
</ul>
<p class="caption"><span class="caption-text">Python API</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../torch.html">torch</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../nn.html">torch.nn</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../nn.functional.html">torch.nn.functional</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../tensors.html">torch.Tensor</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../tensor_attributes.html">Tensor Attributes</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../tensor_view.html">Tensor Views</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../autograd.html">torch.autograd</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../cuda.html">torch.cuda</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../amp.html">torch.cuda.amp</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../distributed.html">torch.distributed</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../distributions.html">torch.distributions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../hub.html">torch.hub</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../jit.html">torch.jit</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../nn.init.html">torch.nn.init</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../onnx.html">torch.onnx</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../optim.html">torch.optim</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../quantization.html">Quantization</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../rpc/index.html">Distributed RPC Framework</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../random.html">torch.random</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../sparse.html">torch.sparse</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../storage.html">torch.Storage</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../bottleneck.html">torch.utils.bottleneck</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../checkpoint.html">torch.utils.checkpoint</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../cpp_extension.html">torch.utils.cpp_extension</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../data.html">torch.utils.data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../dlpack.html">torch.utils.dlpack</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../model_zoo.html">torch.utils.model_zoo</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../tensorboard.html">torch.utils.tensorboard</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../type_info.html">Type Info</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../named_tensor.html">Named Tensors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../name_inference.html">Named Tensors operator coverage</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../__config__.html">torch.__config__</a></li>
</ul>
<p class="caption"><span class="caption-text">Libraries</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="https://pytorch.org/audio">torchaudio</a></li>
<li class="toctree-l1"><a class="reference external" href="https://pytorch.org/text">torchtext</a></li>
<li class="toctree-l1"><a class="reference external" href="https://pytorch.org/elastic/">TorchElastic</a></li>
<li class="toctree-l1"><a class="reference external" href="https://pytorch.org/serve">TorchServe</a></li>
<li class="toctree-l1"><a class="reference external" href="http://pytorch.org/xla/">PyTorch on XLA Devices</a></li>
</ul>
<p class="caption"><span class="caption-text">Community</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../community/contribution_guide.html">PyTorch Contribution Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../community/governance.html">PyTorch Governance</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../community/persons_of_interest.html">PyTorch Governance | Persons of Interest</a></li>
</ul>

            
          

        </div>
      </div>
    </nav>

    <div class="pytorch-container">
      <div class="pytorch-page-level-bar" id="pytorch-page-level-bar">
        <div class="pytorch-breadcrumbs-wrapper">
          















<div role="navigation" aria-label="breadcrumbs navigation">

  <ul class="pytorch-breadcrumbs">
    
      <li>
        <a href="../../../index.html">
          
            Docs
          
        </a> &gt;
      </li>

        
          <li><a href="../../index.html">Module code</a> &gt;</li>
        
          <li><a href="../../torch.html">torch</a> &gt;</li>
        
          <li><a href="../quantization.html">torch.quantization</a> &gt;</li>
        
      <li>torch.quantization.observer</li>
    
    
      <li class="pytorch-breadcrumbs-aside">
        
      </li>
    
  </ul>

  
</div>
        </div>

        <div class="pytorch-shortcuts-wrapper" id="pytorch-shortcuts-wrapper">
          Shortcuts
        </div>
      </div>

      <section data-toggle="wy-nav-shift" id="pytorch-content-wrap" class="pytorch-content-wrap">
        <div class="pytorch-content-left">

        
          
          <div class="rst-content">
          
            <div role="main" class="main-content" itemscope="itemscope" itemtype="http://schema.org/Article">
             <article itemprop="articleBody" id="pytorch-article" class="pytorch-article">
              
  <h1>Source code for torch.quantization.observer</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">absolute_import</span><span class="p">,</span> <span class="n">division</span><span class="p">,</span> <span class="n">print_function</span><span class="p">,</span> <span class="n">unicode_literals</span>

<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">warnings</span>
<span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABCMeta</span><span class="p">,</span> <span class="n">abstractmethod</span>
<span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">partial</span>

<span class="kn">import</span> <span class="nn">torch</span>
<span class="kn">import</span> <span class="nn">torch.nn</span> <span class="k">as</span> <span class="nn">nn</span>
<span class="kn">from</span> <span class="nn">torch._jit_internal</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span>

<span class="k">def</span> <span class="nf">_with_args</span><span class="p">(</span><span class="n">cls_or_self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Wrapper that allows creation of class factories.</span>

<span class="sd">    This can be useful when there is a need to create classes with the same</span>
<span class="sd">    constructor arguments, but different instances.</span>

<span class="sd">    .. Example::</span>

<span class="sd">        &gt;&gt;&gt; Foo.with_args = classmethod(_with_args)</span>
<span class="sd">        &gt;&gt;&gt; foo_builder = Foo.with_args(a=3, b=4).with_args(answer=42)</span>
<span class="sd">        &gt;&gt;&gt; foo_instance1 = foo_builder()</span>
<span class="sd">        &gt;&gt;&gt; foo_instance2 = foo_builder()</span>
<span class="sd">        &gt;&gt;&gt; id(foo_instance1) == id(foo_instance2)</span>
<span class="sd">        False</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">class</span> <span class="nc">_PartialWrapper</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
        <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">p</span> <span class="o">=</span> <span class="n">p</span>

        <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">keywords</span><span class="p">):</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">keywords</span><span class="p">)</span>

        <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">p</span><span class="o">.</span><span class="fm">__repr__</span><span class="p">()</span>

        <span class="n">with_args</span> <span class="o">=</span> <span class="n">_with_args</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">_PartialWrapper</span><span class="p">(</span><span class="n">partial</span><span class="p">(</span><span class="n">cls_or_self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">r</span>


<span class="n">ABC</span> <span class="o">=</span> <span class="n">ABCMeta</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="s2">&quot;ABC&quot;</span><span class="p">),</span> <span class="p">(</span><span class="nb">object</span><span class="p">,),</span> <span class="p">{})</span>  <span class="c1"># compatible with Python 2 *and* 3:</span>


<span class="k">class</span> <span class="nc">ObserverBase</span><span class="p">(</span><span class="n">ABC</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Base observer Module.</span>
<span class="sd">    Any observer implementation should derive from this class.</span>

<span class="sd">    Concrete observers should follow the same API. In forward, they will update</span>
<span class="sd">    the statistics of the observed Tensor. And they should provide a</span>
<span class="sd">    `calculate_qparams` function that computes the quantization parameters given</span>
<span class="sd">    the collected statistics.</span>

<span class="sd">    Args:</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dtype</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ObserverBase</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">=</span> <span class="n">dtype</span>

    <span class="nd">@abstractmethod</span>
    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="k">pass</span>

    <span class="nd">@abstractmethod</span>
    <span class="k">def</span> <span class="nf">calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">pass</span>

    <span class="c1"># Returns all quantization parameters that&#39;s needed</span>
    <span class="c1"># for a quantize function call</span>
    <span class="c1"># For instance, per channel obsserver will return</span>
    <span class="c1"># scales, zero_points and axis</span>
    <span class="nd">@abstractmethod</span>
    <span class="k">def</span> <span class="nf">get_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">pass</span>

    <span class="n">with_args</span> <span class="o">=</span> <span class="nb">classmethod</span><span class="p">(</span><span class="n">_with_args</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">_ObserverBase</span><span class="p">(</span><span class="n">ObserverBase</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Internal common base for all qint/quint8 observers.</span>

<span class="sd">    This base is for commonly used paramters used internally.</span>
<span class="sd">    Users should use `~torch.quantization.observer.ObserverBase` as a base class</span>
<span class="sd">    for custom observers.</span>

<span class="sd">    Args:</span>
<span class="sd">        dtype: Quantized data type.</span>
<span class="sd">        qscheme: Quantization scheme to be used.</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit.</span>
<span class="sd">                      This is sometimes required to avoid instruction overflow.</span>

<span class="sd">    .. warning::</span>

<span class="sd">        :attr:`dtype` can only take ``torch.qint8`` or ``torch.quint8``.</span>

<span class="sd">    .. warning::</span>

<span class="sd">        :attr:`qscheme` can only take one of the following options:</span>

<span class="sd">        - ``torch.per_tensor_affine``</span>
<span class="sd">        - ``torch.per_tensor_symmetric``</span>
<span class="sd">        - ``torch.per_channel_affine``</span>
<span class="sd">        - ``torch.per_channel_symmetric``</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span> <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_affine</span><span class="p">,</span>
                 <span class="n">reduce_range</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">_ObserverBase</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">=</span> <span class="n">qscheme</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span> <span class="o">=</span> <span class="n">reduce_range</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">eps</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">finfo</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">float32</span><span class="p">)</span><span class="o">.</span><span class="n">eps</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="ow">in</span> <span class="p">(</span>
            <span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_affine</span><span class="p">,</span>
            <span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_symmetric</span><span class="p">,</span>
            <span class="n">torch</span><span class="o">.</span><span class="n">per_channel_affine</span><span class="p">,</span>
            <span class="n">torch</span><span class="o">.</span><span class="n">per_channel_symmetric</span><span class="p">,</span>
        <span class="p">),</span> <span class="s2">&quot;Default Observer only works for per_tensor_affine, </span><span class="se">\</span>
<span class="s2">                per_tensor_symmetric, per_channel_affine and </span><span class="se">\</span>
<span class="s2">                per_channel_symmetric quantization scheme&quot;</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="ow">in</span> <span class="p">(</span>
            <span class="n">torch</span><span class="o">.</span><span class="n">qint8</span><span class="p">,</span>
            <span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span>
        <span class="p">),</span> <span class="s2">&quot;Default Observer only works for qint8 and quint8 data type&quot;</span>

    <span class="k">def</span> <span class="nf">_calculate_per_channel_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">min_vals</span><span class="p">,</span> <span class="n">max_vals</span><span class="p">):</span>
        <span class="c1"># type: (Tensor, Tensor) -&gt; Tuple[Tensor, Tensor]</span>
        <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Calculates the per channel quantization parameters, given min and max</span>
<span class="sd">        value tensors.</span>

<span class="sd">        Args:</span>
<span class="sd">            min_vals: Minimum values per channel</span>
<span class="sd">            max_vals: Maximum values per channel</span>

<span class="sd">        Returns:</span>
<span class="sd">            scales: Per channel scales tensor of shape (#channels,)</span>
<span class="sd">            zero_points: Per channel zero points tensor of shape (#channels,)</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">min_vals</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">max_vals</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">warnings</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span>
                <span class="s2">&quot;must run observer before calling calculate_qparams.</span><span class="se">\</span>
<span class="s2">                                    Returning default scale and zero point &quot;</span>
            <span class="p">)</span>
            <span class="k">return</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mf">1.0</span><span class="p">]),</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mi">0</span><span class="p">])</span>

        <span class="n">diff</span> <span class="o">=</span> <span class="n">min_vals</span> <span class="o">&lt;=</span> <span class="n">max_vals</span>
        <span class="k">assert</span> <span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">diff</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">diff</span><span class="p">)),</span> <span class="s2">&quot;min_vals should be less than max_vals for indices.&quot;</span>

        <span class="n">scales</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">empty</span><span class="p">(</span><span class="n">min_vals</span><span class="o">.</span><span class="n">size</span><span class="p">(),</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float32</span><span class="p">)</span>
        <span class="n">zero_points</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">empty</span><span class="p">(</span><span class="n">min_vals</span><span class="o">.</span><span class="n">size</span><span class="p">(),</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">int64</span><span class="p">)</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">qint8</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="o">-</span><span class="mi">64</span><span class="p">,</span> <span class="mi">63</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="o">-</span><span class="mi">128</span><span class="p">,</span> <span class="mi">127</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">127</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span>

        <span class="n">max_vals</span><span class="p">,</span> <span class="n">min_vals</span> <span class="o">=</span> <span class="n">max_vals</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">),</span> <span class="n">min_vals</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>

        <span class="n">min_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">min_vals</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mf">0.</span><span class="p">],</span> <span class="n">device</span><span class="o">=</span><span class="n">min_vals</span><span class="o">.</span><span class="n">device</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">))</span>
        <span class="n">max_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">max_vals</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mf">0.</span><span class="p">],</span> <span class="n">device</span><span class="o">=</span><span class="n">max_vals</span><span class="o">.</span><span class="n">device</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">))</span>
        <span class="k">if</span> <span class="n">torch</span><span class="o">.</span><span class="n">equal</span><span class="p">(</span><span class="n">max_vals</span><span class="p">,</span> <span class="n">min_vals</span><span class="p">):</span>
            <span class="n">scales</span><span class="o">.</span><span class="n">fill_</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)</span>
            <span class="n">zero_points</span><span class="o">.</span><span class="n">fill_</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_symmetric</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">per_channel_symmetric</span><span class="p">:</span>
                <span class="n">max_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="o">-</span><span class="n">min_vals</span><span class="p">,</span> <span class="n">max_vals</span><span class="p">)</span>
                <span class="n">scales</span> <span class="o">=</span> <span class="n">max_vals</span> <span class="o">/</span> <span class="p">((</span><span class="n">qmax</span> <span class="o">-</span> <span class="n">qmin</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span>
                <span class="n">scales</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">scales</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">eps</span><span class="p">],</span> <span class="n">device</span><span class="o">=</span><span class="n">scales</span><span class="o">.</span><span class="n">device</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">scales</span><span class="o">.</span><span class="n">dtype</span><span class="p">))</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">qint8</span><span class="p">:</span>
                    <span class="n">zp</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">zp</span> <span class="o">=</span> <span class="mi">128</span>
                <span class="n">zero_points</span><span class="o">.</span><span class="n">fill_</span><span class="p">(</span><span class="n">zp</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">scales</span> <span class="o">=</span> <span class="p">(</span><span class="n">max_vals</span> <span class="o">-</span> <span class="n">min_vals</span><span class="p">)</span> <span class="o">/</span> <span class="nb">float</span><span class="p">(</span><span class="n">qmax</span> <span class="o">-</span> <span class="n">qmin</span><span class="p">)</span>
                <span class="n">scales</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">scales</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">eps</span><span class="p">],</span> <span class="n">device</span><span class="o">=</span><span class="n">scales</span><span class="o">.</span><span class="n">device</span><span class="p">))</span>
                <span class="n">zero_points</span> <span class="o">=</span> <span class="n">qmin</span> <span class="o">-</span> <span class="n">torch</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="n">min_vals</span> <span class="o">/</span> <span class="n">scales</span><span class="p">)</span>
                <span class="n">zero_points</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">zero_points</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="n">qmin</span><span class="p">],</span> <span class="n">dtype</span><span class="o">=</span><span class="n">zero_points</span><span class="o">.</span><span class="n">dtype</span><span class="p">,</span> <span class="n">device</span><span class="o">=</span><span class="n">zero_points</span><span class="o">.</span><span class="n">device</span><span class="p">))</span>
                <span class="n">zero_points</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">zero_points</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="n">qmax</span><span class="p">],</span> <span class="n">dtype</span><span class="o">=</span><span class="n">zero_points</span><span class="o">.</span><span class="n">dtype</span><span class="p">,</span> <span class="n">device</span><span class="o">=</span><span class="n">zero_points</span><span class="o">.</span><span class="n">device</span><span class="p">))</span>
                <span class="n">zero_points</span> <span class="o">=</span> <span class="n">zero_points</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">int64</span><span class="p">)</span>
        <span class="n">scales</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">scales</span><span class="p">,</span> <span class="n">zero_points</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">_calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">min_val</span><span class="p">,</span> <span class="n">max_val</span><span class="p">):</span>
        <span class="c1"># type: (Tensor, Tensor) -&gt; Tuple[Tensor, Tensor]</span>
        <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Calculates the per tensor quantization parameters, given the min/max.</span>

<span class="sd">        Args:</span>
<span class="sd">            min_val: Per tensor minimum value</span>
<span class="sd">            max_val: Per tensor maximum value</span>

<span class="sd">        Returns:</span>
<span class="sd">            scale: Scale as a tensor of shape (1,)</span>
<span class="sd">            zero_point: Zero point as a tensor of shape (1,)</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">max_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">min_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">warnings</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s2">&quot;Must run observer before calling calculate_qparams.</span><span class="se">\</span>
<span class="s2">                           Returning default scale and zero point.&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mf">1.0</span><span class="p">]),</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mi">0</span><span class="p">])</span>

        <span class="k">assert</span> <span class="n">min_val</span> <span class="o">&lt;=</span> <span class="n">max_val</span><span class="p">,</span> <span class="s2">&quot;min </span><span class="si">{}</span><span class="s2"> should be less than max </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
            <span class="n">min_val</span><span class="p">,</span> <span class="n">max_val</span>
        <span class="p">)</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">qint8</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="o">-</span><span class="mi">64</span><span class="p">,</span> <span class="mi">63</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="o">-</span><span class="mi">128</span><span class="p">,</span> <span class="mi">127</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">127</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">qmin</span><span class="p">,</span> <span class="n">qmax</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span>

        <span class="n">max_val</span><span class="p">,</span> <span class="n">min_val</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">max_val</span><span class="p">),</span> <span class="nb">float</span><span class="p">(</span><span class="n">min_val</span><span class="p">)</span>
        <span class="n">min_val</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">min_val</span><span class="p">)</span>
        <span class="n">max_val</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">max_val</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">max_val</span> <span class="o">==</span> <span class="n">min_val</span><span class="p">:</span>
            <span class="n">scale</span> <span class="o">=</span> <span class="mf">1.0</span>
            <span class="n">zero_point</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_symmetric</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">per_channel_symmetric</span><span class="p">:</span>
                <span class="n">max_val</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="o">-</span><span class="n">min_val</span><span class="p">,</span> <span class="n">max_val</span><span class="p">)</span>
                <span class="n">scale</span> <span class="o">=</span> <span class="n">max_val</span> <span class="o">/</span> <span class="p">((</span><span class="n">qmax</span> <span class="o">-</span> <span class="n">qmin</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span>
                <span class="n">scale</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">scale</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">eps</span><span class="p">)</span>
                <span class="n">zero_point</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">qint8</span> <span class="k">else</span> <span class="mi">128</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">scale</span> <span class="o">=</span> <span class="p">(</span><span class="n">max_val</span> <span class="o">-</span> <span class="n">min_val</span><span class="p">)</span> <span class="o">/</span> <span class="nb">float</span><span class="p">(</span><span class="n">qmax</span> <span class="o">-</span> <span class="n">qmin</span><span class="p">)</span>
                <span class="n">scale</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">scale</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">eps</span><span class="p">)</span>
                <span class="n">zero_point</span> <span class="o">=</span> <span class="n">qmin</span> <span class="o">-</span> <span class="nb">round</span><span class="p">(</span><span class="n">min_val</span> <span class="o">/</span> <span class="n">scale</span><span class="p">)</span>
                <span class="n">zero_point</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">qmin</span><span class="p">,</span> <span class="n">zero_point</span><span class="p">)</span>
                <span class="n">zero_point</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">qmax</span><span class="p">,</span> <span class="n">zero_point</span><span class="p">)</span>
                <span class="n">zero_point</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">zero_point</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="n">scale</span><span class="p">]),</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="n">zero_point</span><span class="p">])</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">get_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Get all quantization parameters needed for quantize call&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">calculate_qparams</span><span class="p">()</span>

<div class="viewcode-block" id="MinMaxObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.MinMaxObserver">[docs]</a><span class="k">class</span> <span class="nc">MinMaxObserver</span><span class="p">(</span><span class="n">_ObserverBase</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Observer module for computing the quantization parameters based on the</span>
<span class="sd">    running min and max values.</span>

<span class="sd">    This observer uses the tensor min/max statistics to compute the quantization</span>
<span class="sd">    parameters. The module records the running minimum and maximum of incoming</span>
<span class="sd">    tensors, and uses this statistic to compute the quantization parameters.</span>

<span class="sd">    Args:</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">        qscheme: Quantization scheme to be used</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit</span>

<span class="sd">    Given running min/max as :math:`x_\text{min}` and :math:`x_\text{max}`,</span>
<span class="sd">    scale :math:`s` and zero point :math:`z` are computed as:</span>

<span class="sd">    The running minimum/maximum :math:`x_\text{min/max}` is computed as:</span>

<span class="sd">    .. math::</span>

<span class="sd">        \begin{array}{ll}</span>
<span class="sd">        x_\text{min} &amp;= \begin{cases}</span>
<span class="sd">            \min(X) &amp; \text{if~}x_\text{min} = \text{None} \\</span>
<span class="sd">            \min\left(x_\text{min}, \min(X)\right) &amp; \text{otherwise}</span>
<span class="sd">        \end{cases}\\</span>
<span class="sd">        x_\text{max} &amp;= \begin{cases}</span>
<span class="sd">            \max(X) &amp; \text{if~}x_\text{max} = \text{None} \\</span>
<span class="sd">            \max\left(x_\text{max}, \max(X)\right) &amp; \text{otherwise}</span>
<span class="sd">        \end{cases}\\</span>
<span class="sd">        \end{array}</span>

<span class="sd">    where :math:`X` is the observed tensor.</span>

<span class="sd">    The scale :math:`s` and zero point :math:`z` are then computed as:</span>

<span class="sd">    .. math::</span>

<span class="sd">        \begin{aligned}</span>
<span class="sd">            \text{if Symmetric:}&amp;\\</span>
<span class="sd">            &amp;s = 2 \max(|x_\text{min}|, x_\text{max}) /</span>
<span class="sd">                \left( Q_\text{max} - Q_\text{min} \right) \\</span>
<span class="sd">            &amp;z = \begin{cases}</span>
<span class="sd">                0 &amp; \text{if dtype is qint8} \\</span>
<span class="sd">                128 &amp; \text{otherwise}</span>
<span class="sd">            \end{cases}\\</span>
<span class="sd">            \text{Otherwise:}&amp;\\</span>
<span class="sd">                &amp;s = \left( x_\text{max} - x_\text{min}  \right ) /</span>
<span class="sd">                    \left( Q_\text{max} - Q_\text{min} \right ) \\</span>
<span class="sd">                &amp;z = Q_\text{min} - \text{round}(x_\text{min} / s)</span>
<span class="sd">        \end{aligned}</span>

<span class="sd">    where :math:`Q_\text{min}` and :math:`Q_\text{max}` are the minimum and</span>
<span class="sd">    maximum of the quantized data type.</span>

<span class="sd">    .. warning:: Only works with ``torch.per_tensor_symmetric`` quantization scheme</span>

<span class="sd">    .. warning:: :attr:`dtype` can only take ``torch.qint8`` or ``torch.quint8``.</span>

<span class="sd">    .. note:: If the running minimum equals to the running maximum, the scale</span>
<span class="sd">              and zero_point are set to 1.0 and 0.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span> <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_affine</span><span class="p">,</span>
                 <span class="n">reduce_range</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
        <span class="c1"># For x86 quantized kernels, we need to ensure that the vpmaddubsw</span>
        <span class="c1"># instruction does not overflow. We allow for a reduce_range argument to</span>
        <span class="c1"># observers that reduces the quantized range to (0,127) or (-64, 63).</span>
        <span class="c1"># For more details see aten/src/ATen/native/quantized/cpu/qconv.cpp</span>
        <span class="c1"># This is not an optimal choice for non x86 backends as it loses a bit</span>
        <span class="c1"># of precision for activations.</span>

        <span class="nb">super</span><span class="p">(</span><span class="n">MinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">,</span>
                                             <span class="n">qscheme</span><span class="o">=</span><span class="n">qscheme</span><span class="p">,</span>
                                             <span class="n">reduce_range</span><span class="o">=</span><span class="n">reduce_range</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;min_val&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([]))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;max_val&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([]))</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_symmetric</span> <span class="ow">and</span> \
           <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span> <span class="ow">and</span> \
           <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">&quot;Cannot reduce range for symmetric </span><span class="se">\</span>
<span class="s2">                                       quantization for quint8&quot;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_orig</span><span class="p">):</span>
        <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Records the running minimum and maximum of ``x``.&quot;&quot;&quot;</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">x_orig</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>  <span class="c1"># avoid keeping autograd tape</span>
        <span class="n">min_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span>
        <span class="n">max_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span>
        <span class="k">if</span> <span class="n">min_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">max_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">min_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">max_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">min_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">min_val</span><span class="p">)</span>
            <span class="n">max_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">max_val</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">=</span> <span class="n">min_val</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span> <span class="o">=</span> <span class="n">max_val</span>
        <span class="k">return</span> <span class="n">x_orig</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Calculates the quantization parameters.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">min_val</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span><span class="p">)</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">extra_repr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s2">&quot;min_val=</span><span class="si">{}</span><span class="s2">, max_val=</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">min_val</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">_save_to_state_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">keep_vars</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">MinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_save_to_state_dict</span><span class="p">(</span><span class="n">destination</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">keep_vars</span><span class="p">)</span>
        <span class="n">destination</span><span class="p">[</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">&#39;min_val&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span>
        <span class="n">destination</span><span class="p">[</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">&#39;max_val&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span>

    <span class="k">def</span> <span class="nf">_load_from_state_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state_dict</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">local_metadata</span><span class="p">,</span> <span class="n">strict</span><span class="p">,</span>
                              <span class="n">missing_keys</span><span class="p">,</span> <span class="n">unexpected_keys</span><span class="p">,</span> <span class="n">error_msgs</span><span class="p">):</span>

        <span class="n">local_state</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;min_val&#39;</span><span class="p">,</span> <span class="s1">&#39;max_val&#39;</span><span class="p">]</span>
        <span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">local_state</span><span class="p">:</span>
            <span class="n">key</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="n">name</span>
            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">state_dict</span><span class="p">:</span>
                <span class="n">val</span> <span class="o">=</span> <span class="n">state_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
                <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span>
            <span class="k">elif</span> <span class="n">strict</span><span class="p">:</span>
                <span class="n">missing_keys</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">MinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_load_from_state_dict</span><span class="p">(</span><span class="n">state_dict</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">local_metadata</span><span class="p">,</span> <span class="n">strict</span><span class="p">,</span>
                                                          <span class="n">missing_keys</span><span class="p">,</span> <span class="n">unexpected_keys</span><span class="p">,</span> <span class="n">error_msgs</span><span class="p">)</span></div>


<div class="viewcode-block" id="MovingAverageMinMaxObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.MovingAverageMinMaxObserver">[docs]</a><span class="k">class</span> <span class="nc">MovingAverageMinMaxObserver</span><span class="p">(</span><span class="n">MinMaxObserver</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Observer module for computing the quantization parameters based on the</span>
<span class="sd">    moving average of the min and max values.</span>

<span class="sd">    This observer computes the quantization parameters based on the moving</span>
<span class="sd">    averages of minimums and maximums of the incoming tensors. The module</span>
<span class="sd">    records the average minimum and maximum of incoming tensors, and uses this</span>
<span class="sd">    statistic to compute the quantization parameters.</span>

<span class="sd">    Args:</span>
<span class="sd">        averaging_constant: Averaging constant for min/max.</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">        qscheme: Quantization scheme to be used</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit</span>

<span class="sd">    The moving average min/max is computed as follows</span>

<span class="sd">    .. math::</span>

<span class="sd">        \begin{array}{ll}</span>
<span class="sd">                x_\text{min} = \begin{cases}</span>
<span class="sd">                    \min(X) &amp; \text{if~}x_\text{min} = \text{None} \\</span>
<span class="sd">                    (1 - c) x_\text{min} + c \min(X) &amp; \text{otherwise}</span>
<span class="sd">                \end{cases}\\</span>
<span class="sd">                x_\text{max} = \begin{cases}</span>
<span class="sd">                    \max(X) &amp; \text{if~}x_\text{max} = \text{None} \\</span>
<span class="sd">                    (1 - c) x_\text{max} + c \max(X) &amp; \text{otherwise}</span>
<span class="sd">                \end{cases}\\</span>
<span class="sd">        \end{array}</span>

<span class="sd">    where :math:`x_\text{min/max}` is the running average min/max, :math:`X` is</span>
<span class="sd">    is the incoming tensor, and :math:`c` is the ``averaging_constant``.</span>

<span class="sd">    The scale and zero point are then computed as in</span>
<span class="sd">    :class:`~torch.quantization.observer.MinMaxObserver`.</span>

<span class="sd">    .. note:: Only works with ``torch.per_tensor_affine`` quantization shceme.</span>

<span class="sd">    .. note:: If the running minimum equals to the running maximum, the scale</span>
<span class="sd">              and zero_point are set to 1.0 and 0.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">averaging_constant</span><span class="o">=</span><span class="mf">0.01</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span>
                 <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_affine</span><span class="p">,</span> <span class="n">reduce_range</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">averaging_constant</span> <span class="o">=</span> <span class="n">averaging_constant</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">MovingAverageMinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">,</span>
                                                          <span class="n">qscheme</span><span class="o">=</span><span class="n">qscheme</span><span class="p">,</span>
                                                          <span class="n">reduce_range</span><span class="o">=</span><span class="n">reduce_range</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_orig</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">x_orig</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>  <span class="c1"># avoid keeping autograd tape</span>
        <span class="n">min_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span>
        <span class="n">max_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span>
        <span class="k">if</span> <span class="n">min_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">max_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">min_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">max_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">min_val</span> <span class="o">=</span> <span class="n">min_val</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">averaging_constant</span> <span class="o">*</span> <span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">min_val</span><span class="p">)</span>
            <span class="n">max_val</span> <span class="o">=</span> <span class="n">max_val</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">averaging_constant</span> <span class="o">*</span> <span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">max_val</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">=</span> <span class="n">min_val</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span> <span class="o">=</span> <span class="n">max_val</span>
        <span class="k">return</span> <span class="n">x_orig</span></div>


<div class="viewcode-block" id="PerChannelMinMaxObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.PerChannelMinMaxObserver">[docs]</a><span class="k">class</span> <span class="nc">PerChannelMinMaxObserver</span><span class="p">(</span><span class="n">_ObserverBase</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Observer module for computing the quantization parameters based on the</span>
<span class="sd">    running per channel min and max values.</span>

<span class="sd">    This observer uses the tensor min/max statistics to compute the per channel</span>
<span class="sd">    quantization parameters. The module records the running minimum and maximum</span>
<span class="sd">    of incoming tensors, and uses this statistic to compute the quantization</span>
<span class="sd">    parameters.</span>

<span class="sd">    Args:</span>
<span class="sd">        ch_axis: Channel axis</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">        qscheme: Quantization scheme to be used</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit</span>

<span class="sd">    The quantization parameters are computed the same way as in</span>
<span class="sd">    :class:`~torch.quantization.observer.MinMaxObserver`, with the difference</span>
<span class="sd">    that the running min/max values are stored per channel.</span>
<span class="sd">    Scales and zero points are thus computed per channel as well.</span>

<span class="sd">    .. note:: If the running minimum equals to the running maximum, the scales</span>
<span class="sd">              and zero_points are set to 1.0 and 0.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ch_axis</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span>
                 <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_channel_affine</span><span class="p">,</span> <span class="n">reduce_range</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">PerChannelMinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">,</span>
                                                       <span class="n">qscheme</span><span class="o">=</span><span class="n">qscheme</span><span class="p">,</span>
                                                       <span class="n">reduce_range</span><span class="o">=</span><span class="n">reduce_range</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">ch_axis</span> <span class="o">=</span> <span class="n">ch_axis</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;min_vals&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([]))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;max_vals&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([]))</span>
        <span class="k">if</span> <span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">qscheme</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">per_channel_symmetric</span>
            <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">reduce_range</span>
            <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">dtype</span> <span class="o">==</span> <span class="n">torch</span><span class="o">.</span><span class="n">quint8</span>
        <span class="p">):</span>
            <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span>
                <span class="s2">&quot;Cannot reduce range for symmetric quantization for quint8&quot;</span>
            <span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_orig</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_forward</span><span class="p">(</span><span class="n">x_orig</span><span class="p">)</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">ignore</span>
    <span class="k">def</span> <span class="nf">_forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_orig</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">x_orig</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>  <span class="c1"># avoid keeping autograd tape</span>
        <span class="n">min_vals</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span>
        <span class="n">max_vals</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span>
        <span class="n">x_dim</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">size</span><span class="p">()</span>

        <span class="n">new_axis_list</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">x_dim</span><span class="p">)))</span>
        <span class="n">new_axis_list</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">ch_axis</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">new_axis_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ch_axis</span>
        <span class="n">y</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">permute</span><span class="p">(</span><span class="nb">tuple</span><span class="p">(</span><span class="n">new_axis_list</span><span class="p">))</span>
        <span class="n">y</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">flatten</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">start_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">min_vals</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">max_vals</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">min_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">max_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">min_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span> <span class="n">min_vals</span><span class="p">)</span>
            <span class="n">max_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span> <span class="n">max_vals</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span> <span class="o">=</span> <span class="n">min_vals</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span> <span class="o">=</span> <span class="n">max_vals</span>
        <span class="k">return</span> <span class="n">x_orig</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calculate_per_channel_qparams</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span><span class="p">)</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">get_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">scales</span><span class="p">,</span> <span class="n">zero_points</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">calculate_qparams</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">scales</span><span class="p">,</span> <span class="n">zero_points</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">ch_axis</span>

    <span class="k">def</span> <span class="nf">extra_repr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s2">&quot;min_val=</span><span class="si">{}</span><span class="s2">, max_val=</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">_save_to_state_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">keep_vars</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">PerChannelMinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_save_to_state_dict</span><span class="p">(</span><span class="n">destination</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">keep_vars</span><span class="p">)</span>
        <span class="n">destination</span><span class="p">[</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">&#39;min_vals&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span>
        <span class="n">destination</span><span class="p">[</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">&#39;max_vals&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span>

    <span class="k">def</span> <span class="nf">_load_from_state_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state_dict</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">local_metadata</span><span class="p">,</span> <span class="n">strict</span><span class="p">,</span>
                              <span class="n">missing_keys</span><span class="p">,</span> <span class="n">unexpected_keys</span><span class="p">,</span> <span class="n">error_msgs</span><span class="p">):</span>
        <span class="n">local_state</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;min_vals&#39;</span><span class="p">,</span> <span class="s1">&#39;max_vals&#39;</span><span class="p">]</span>
        <span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">local_state</span><span class="p">:</span>
            <span class="n">key</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="n">name</span>
            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">state_dict</span><span class="p">:</span>
                <span class="n">val</span> <span class="o">=</span> <span class="n">state_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
                <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span>
            <span class="k">elif</span> <span class="n">strict</span><span class="p">:</span>
                <span class="n">missing_keys</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">PerChannelMinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_load_from_state_dict</span><span class="p">(</span><span class="n">state_dict</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">local_metadata</span><span class="p">,</span> <span class="n">strict</span><span class="p">,</span>
                                                                    <span class="n">missing_keys</span><span class="p">,</span> <span class="n">unexpected_keys</span><span class="p">,</span> <span class="n">error_msgs</span><span class="p">)</span></div>

<div class="viewcode-block" id="MovingAveragePerChannelMinMaxObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.MovingAveragePerChannelMinMaxObserver">[docs]</a><span class="k">class</span> <span class="nc">MovingAveragePerChannelMinMaxObserver</span><span class="p">(</span><span class="n">PerChannelMinMaxObserver</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Observer module for computing the quantization parameters based on the</span>
<span class="sd">    running per channel min and max values.</span>

<span class="sd">    This observer uses the tensor min/max statistics to compute the per channel</span>
<span class="sd">    quantization parameters. The module records the running minimum and maximum</span>
<span class="sd">    of incoming tensors, and uses this statistic to compute the quantization</span>
<span class="sd">    parameters.</span>

<span class="sd">    Args:</span>
<span class="sd">        averaging_constant: Averaging constant for min/max.</span>
<span class="sd">        ch_axis: Channel axis</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">        qscheme: Quantization scheme to be used</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit</span>

<span class="sd">    The quantization parameters are computed the same way as in</span>
<span class="sd">    :class:`~torch.quantization.observer.MovingAverageMinMaxObserver`, with the</span>
<span class="sd">    difference that the running min/max values are stored per channel.</span>
<span class="sd">    Scales and zero points are thus computed per channel as well.</span>

<span class="sd">    .. note:: If the running minimum equals to the running maximum, the scales</span>
<span class="sd">              and zero_points are set to 1.0 and 0.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">averaging_constant</span><span class="o">=</span><span class="mf">0.01</span><span class="p">,</span> <span class="n">ch_axis</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span>
                 <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_channel_affine</span><span class="p">,</span> <span class="n">reduce_range</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">MovingAveragePerChannelMinMaxObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
            <span class="n">ch_axis</span><span class="o">=</span><span class="n">ch_axis</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">,</span> <span class="n">qscheme</span><span class="o">=</span><span class="n">qscheme</span><span class="p">,</span>
            <span class="n">reduce_range</span><span class="o">=</span><span class="n">reduce_range</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">averaging_constant</span> <span class="o">=</span> <span class="n">averaging_constant</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_orig</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">x_orig</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>  <span class="c1"># avoid keeping autograd tape</span>
        <span class="n">min_vals</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span>
        <span class="n">max_vals</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span>
        <span class="n">x_dim</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">size</span><span class="p">()</span>

        <span class="n">new_axis_list</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">x_dim</span><span class="p">)))</span>
        <span class="n">new_axis_list</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">ch_axis</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">new_axis_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ch_axis</span>
        <span class="n">y</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">permute</span><span class="p">(</span><span class="nb">tuple</span><span class="p">(</span><span class="n">new_axis_list</span><span class="p">))</span>
        <span class="n">y</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">flatten</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">start_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">min_vals</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">max_vals</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">min_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">max_vals</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">min_vals</span> <span class="o">=</span> <span class="n">min_vals</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">averaging_constant</span> <span class="o">*</span> <span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">min_vals</span><span class="p">)</span>
            <span class="n">max_vals</span> <span class="o">=</span> <span class="n">max_vals</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">averaging_constant</span> <span class="o">*</span> <span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">max_vals</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">min_vals</span> <span class="o">=</span> <span class="n">min_vals</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_vals</span> <span class="o">=</span> <span class="n">max_vals</span>
        <span class="k">return</span> <span class="n">x_orig</span></div>

<div class="viewcode-block" id="HistogramObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.HistogramObserver">[docs]</a><span class="k">class</span> <span class="nc">HistogramObserver</span><span class="p">(</span><span class="n">_ObserverBase</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    The module records the running histogram of tensor values along with</span>
<span class="sd">    min/max values. ``calculate_qparams`` will calculate scale and zero_point.</span>

<span class="sd">    Args:</span>
<span class="sd">        bins: Number of bins to use for the histogram</span>
<span class="sd">        upsample_rate: Factor by which the histograms are upsampled, this is</span>
<span class="sd">                       used to interpolate histograms with varying ranges across observations</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">        qscheme: Quantization scheme to be used</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit</span>

<span class="sd">    The scale and zero point are computed as follows:</span>

<span class="sd">    1. Create the histogram of the incoming inputs.</span>
<span class="sd">        The histogram is computed continuously, and the ranges per bin change</span>
<span class="sd">        with every new tensor observed.</span>
<span class="sd">    2. Search the distribution in the histogram for optimal min/max values.</span>
<span class="sd">        The search for the min/max values ensures the minimization of the</span>
<span class="sd">        quantization error with respect to the floating point model.</span>
<span class="sd">    3. Compute the scale and zero point the same way as in the</span>
<span class="sd">        :class:`~torch.quantization.MinMaxObserver`</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bins</span><span class="o">=</span><span class="mi">2048</span><span class="p">,</span> <span class="n">upsample_rate</span><span class="o">=</span><span class="mi">128</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">quint8</span><span class="p">,</span>
                 <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_affine</span><span class="p">,</span> <span class="n">reduce_range</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
        <span class="c1"># bins: The number of bins used for histogram calculation.</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">HistogramObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">,</span>
                                                <span class="n">qscheme</span><span class="o">=</span><span class="n">qscheme</span><span class="p">,</span>
                                                <span class="n">reduce_range</span><span class="o">=</span><span class="n">reduce_range</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">bins</span> <span class="o">=</span> <span class="n">bins</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;histogram&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bins</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;min_val&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([]))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;max_val&#39;</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([]))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">dst_nbins</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">**</span> <span class="n">torch</span><span class="o">.</span><span class="n">iinfo</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">dtype</span><span class="p">)</span><span class="o">.</span><span class="n">bits</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">upsample_rate</span> <span class="o">=</span> <span class="n">upsample_rate</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">ignore</span>
    <span class="k">def</span> <span class="nf">_non_linear_param_search</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sa">r</span><span class="sd">&quot;&quot;&quot;Non-linear parameter search.</span>

<span class="sd">        An approximation for L2 error minimization for selecting min/max.</span>
<span class="sd">        By selecting new min/max, we filter out outliers in input distribution.</span>
<span class="sd">        This follows the implementation of NormMinimization::NonlinearQuantizationParamsSearch in</span>
<span class="sd">        caffe2/quantization/server/norm_minimization.cc</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">def</span> <span class="nf">_get_norm</span><span class="p">(</span><span class="n">delta_begin</span><span class="p">,</span> <span class="n">delta_end</span><span class="p">,</span> <span class="n">density</span><span class="p">,</span> <span class="n">norm_type</span><span class="p">):</span>
            <span class="sa">r</span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">            Compute the norm of the values uniformaly distributed between</span>
<span class="sd">            delta_begin and delta_end.</span>

<span class="sd">            norm = density * (integral_{begin, end} x^2)</span>
<span class="sd">                 = density * (end^3 - begin^3) / 3</span>
<span class="sd">            &quot;&quot;&quot;</span>
            <span class="k">assert</span> <span class="n">norm_type</span> <span class="o">==</span> <span class="s2">&quot;L2&quot;</span><span class="p">,</span> <span class="s2">&quot;Only L2 norms are currently supported&quot;</span>
            <span class="n">norm</span> <span class="o">=</span> <span class="mf">0.0</span>
            <span class="k">if</span> <span class="n">norm_type</span> <span class="o">==</span> <span class="s2">&quot;L2&quot;</span><span class="p">:</span>
                <span class="n">norm</span> <span class="o">=</span> <span class="p">(</span>
                    <span class="n">delta_end</span> <span class="o">*</span> <span class="n">delta_end</span> <span class="o">*</span> <span class="n">delta_end</span>
                    <span class="o">-</span> <span class="n">delta_begin</span> <span class="o">*</span> <span class="n">delta_begin</span> <span class="o">*</span> <span class="n">delta_begin</span>
                <span class="p">)</span> <span class="o">/</span> <span class="mi">3</span>
            <span class="k">return</span> <span class="n">density</span> <span class="o">*</span> <span class="n">norm</span>

        <span class="k">def</span> <span class="nf">_compute_quantization_error</span><span class="p">(</span><span class="n">next_start_bin</span><span class="p">,</span> <span class="n">next_end_bin</span><span class="p">,</span> <span class="n">norm_type</span><span class="p">):</span>
            <span class="sa">r</span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">            Compute the quantization error if we use start_bin to end_bin as the</span>
<span class="sd">            min and max to do the quantization.</span>
<span class="sd">            &quot;&quot;&quot;</span>
            <span class="n">bin_width</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_val</span><span class="o">.</span><span class="n">item</span><span class="p">()</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span><span class="o">.</span><span class="n">item</span><span class="p">())</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span>

            <span class="n">norm</span> <span class="o">=</span> <span class="mf">0.0</span>
            <span class="n">dst_bin_width</span> <span class="o">=</span> <span class="n">bin_width</span> <span class="o">*</span> <span class="p">(</span><span class="n">next_end_bin</span> <span class="o">-</span> <span class="n">next_start_bin</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">dst_nbins</span>
            <span class="k">if</span> <span class="n">dst_bin_width</span> <span class="o">==</span> <span class="mf">0.0</span><span class="p">:</span>
                <span class="k">return</span> <span class="mf">0.0</span>
            <span class="k">for</span> <span class="n">src_bin</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bins</span><span class="p">):</span>
                <span class="c1"># distances from the beginning of first dst_bin to the beginning and</span>
                <span class="c1"># end of src_bin</span>
                <span class="n">src_bin_begin</span> <span class="o">=</span> <span class="p">(</span><span class="n">src_bin</span> <span class="o">-</span> <span class="n">next_start_bin</span><span class="p">)</span> <span class="o">*</span> <span class="n">bin_width</span>
                <span class="n">src_bin_end</span> <span class="o">=</span> <span class="n">src_bin_begin</span> <span class="o">+</span> <span class="n">bin_width</span>

                <span class="c1"># which dst_bins the beginning and end of src_bin belong to?</span>
                <span class="n">dst_bin_of_begin</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">dst_nbins</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">max</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">math</span><span class="o">.</span><span class="n">floor</span><span class="p">(</span><span class="n">src_bin_begin</span> <span class="o">/</span> <span class="n">dst_bin_width</span><span class="p">))</span>
                <span class="p">)</span>
                <span class="n">dst_bin_of_end</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">dst_nbins</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">max</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">math</span><span class="o">.</span><span class="n">floor</span><span class="p">(</span><span class="n">src_bin_end</span> <span class="o">/</span> <span class="n">dst_bin_width</span><span class="p">))</span>
                <span class="p">)</span>
                <span class="n">dst_bin_of_begin_center</span> <span class="o">=</span> <span class="p">(</span>
                    <span class="n">dst_bin_of_begin</span> <span class="o">*</span> <span class="n">dst_bin_width</span> <span class="o">+</span> <span class="n">dst_bin_width</span> <span class="o">/</span> <span class="mi">2</span>
                <span class="p">)</span>

                <span class="n">density</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">histogram</span><span class="p">[</span><span class="n">src_bin</span><span class="p">]</span> <span class="o">/</span> <span class="n">bin_width</span>
                <span class="k">if</span> <span class="n">dst_bin_of_begin</span> <span class="o">==</span> <span class="n">dst_bin_of_end</span><span class="p">:</span>
                    <span class="c1"># if src_bin is entirely within 1 dst_bin</span>
                    <span class="n">delta_begin</span> <span class="o">=</span> <span class="n">src_bin_begin</span> <span class="o">-</span> <span class="n">dst_bin_of_begin_center</span>
                    <span class="n">delta_end</span> <span class="o">=</span> <span class="n">src_bin_end</span> <span class="o">-</span> <span class="n">dst_bin_of_begin_center</span>
                    <span class="n">norm</span> <span class="o">=</span> <span class="n">norm</span> <span class="o">+</span> <span class="n">_get_norm</span><span class="p">(</span><span class="n">delta_begin</span><span class="p">,</span> <span class="n">delta_end</span><span class="p">,</span> <span class="n">density</span><span class="p">,</span> <span class="n">norm_type</span><span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">delta_begin</span> <span class="o">=</span> <span class="n">src_bin_begin</span> <span class="o">-</span> <span class="n">dst_bin_of_begin_center</span>
                    <span class="n">delta_end</span> <span class="o">=</span> <span class="n">dst_bin_width</span> <span class="o">/</span> <span class="mi">2</span>
                    <span class="n">norm</span> <span class="o">=</span> <span class="n">norm</span> <span class="o">+</span> <span class="n">_get_norm</span><span class="p">(</span><span class="n">delta_begin</span><span class="p">,</span> <span class="n">delta_end</span><span class="p">,</span> <span class="n">density</span><span class="p">,</span> <span class="n">norm_type</span><span class="p">)</span>

                    <span class="n">norm</span> <span class="o">=</span> <span class="n">norm</span> <span class="o">+</span> <span class="p">(</span><span class="n">dst_bin_of_end</span> <span class="o">-</span> <span class="n">dst_bin_of_begin</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">_get_norm</span><span class="p">(</span>
                        <span class="o">-</span><span class="n">dst_bin_width</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">dst_bin_width</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">density</span><span class="p">,</span> <span class="n">norm_type</span>
                    <span class="p">)</span>

                    <span class="n">dst_bin_of_end_center</span> <span class="o">=</span> <span class="p">(</span>
                        <span class="n">dst_bin_of_end</span> <span class="o">*</span> <span class="n">dst_bin_width</span> <span class="o">+</span> <span class="n">dst_bin_width</span> <span class="o">/</span> <span class="mi">2</span>
                    <span class="p">)</span>

                    <span class="n">delta_begin</span> <span class="o">=</span> <span class="o">-</span><span class="n">dst_bin_width</span> <span class="o">/</span> <span class="mi">2</span>
                    <span class="n">delta_end</span> <span class="o">=</span> <span class="n">src_bin_end</span> <span class="o">-</span> <span class="n">dst_bin_of_end_center</span>
                    <span class="n">norm</span> <span class="o">=</span> <span class="n">norm</span> <span class="o">+</span> <span class="n">_get_norm</span><span class="p">(</span><span class="n">delta_begin</span><span class="p">,</span> <span class="n">delta_end</span><span class="p">,</span> <span class="n">density</span><span class="p">,</span> <span class="n">norm_type</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">norm</span>

        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">histogram</span><span class="o">.</span><span class="n">size</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span><span class="p">,</span> <span class="s2">&quot;bins mistmatch&quot;</span>
        <span class="n">bin_width</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_val</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span><span class="p">)</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span>

        <span class="c1"># cumulative sum</span>
        <span class="n">total</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">histogram</span><span class="p">)</span>
        <span class="n">cSum</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">cumsum</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">histogram</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>

        <span class="n">stepsize</span> <span class="o">=</span> <span class="mf">1e-5</span>  <span class="c1"># granularity</span>
        <span class="n">alpha</span> <span class="o">=</span> <span class="mf">0.0</span>  <span class="c1"># lower bound</span>
        <span class="n">beta</span> <span class="o">=</span> <span class="mf">1.0</span>  <span class="c1"># upper bound</span>
        <span class="n">start_bin</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">end_bin</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span> <span class="o">-</span> <span class="mi">1</span>
        <span class="n">norm_min</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;inf&quot;</span><span class="p">)</span>

        <span class="k">while</span> <span class="n">alpha</span> <span class="o">&lt;</span> <span class="n">beta</span><span class="p">:</span>
            <span class="c1"># Find the next step</span>
            <span class="n">next_alpha</span> <span class="o">=</span> <span class="n">alpha</span> <span class="o">+</span> <span class="n">stepsize</span>
            <span class="n">next_beta</span> <span class="o">=</span> <span class="n">beta</span> <span class="o">-</span> <span class="n">stepsize</span>

            <span class="c1"># find the left and right bins between the quantile bounds</span>
            <span class="n">l</span> <span class="o">=</span> <span class="n">start_bin</span>
            <span class="n">r</span> <span class="o">=</span> <span class="n">end_bin</span>
            <span class="k">while</span> <span class="n">l</span> <span class="o">&lt;</span> <span class="n">end_bin</span> <span class="ow">and</span> <span class="n">cSum</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">next_alpha</span> <span class="o">*</span> <span class="n">total</span><span class="p">:</span>
                <span class="n">l</span> <span class="o">=</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span>
            <span class="k">while</span> <span class="n">r</span> <span class="o">&gt;</span> <span class="n">start_bin</span> <span class="ow">and</span> <span class="n">cSum</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">next_beta</span> <span class="o">*</span> <span class="n">total</span><span class="p">:</span>
                <span class="n">r</span> <span class="o">=</span> <span class="n">r</span> <span class="o">-</span> <span class="mi">1</span>

            <span class="c1"># decide the next move</span>
            <span class="n">next_start_bin</span> <span class="o">=</span> <span class="n">start_bin</span>
            <span class="n">next_end_bin</span> <span class="o">=</span> <span class="n">end_bin</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">-</span> <span class="n">start_bin</span><span class="p">)</span> <span class="o">&gt;</span> <span class="p">(</span><span class="n">end_bin</span> <span class="o">-</span> <span class="n">r</span><span class="p">):</span>
                <span class="c1"># move the start bin</span>
                <span class="n">next_start_bin</span> <span class="o">=</span> <span class="n">l</span>
                <span class="n">alpha</span> <span class="o">=</span> <span class="n">next_alpha</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># move the end bin</span>
                <span class="n">next_end_bin</span> <span class="o">=</span> <span class="n">r</span>
                <span class="n">beta</span> <span class="o">=</span> <span class="n">next_beta</span>

            <span class="k">if</span> <span class="n">next_start_bin</span> <span class="o">==</span> <span class="n">start_bin</span> <span class="ow">and</span> <span class="n">next_end_bin</span> <span class="o">==</span> <span class="n">end_bin</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="c1"># calculate the quantization error using next_start_bin and next_end_bin</span>
            <span class="n">norm</span> <span class="o">=</span> <span class="n">_compute_quantization_error</span><span class="p">(</span><span class="n">next_start_bin</span><span class="p">,</span> <span class="n">next_end_bin</span><span class="p">,</span> <span class="s2">&quot;L2&quot;</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">norm</span> <span class="o">&gt;</span> <span class="n">norm_min</span><span class="p">:</span>
                <span class="k">break</span>
            <span class="n">norm_min</span> <span class="o">=</span> <span class="n">norm</span>
            <span class="n">start_bin</span> <span class="o">=</span> <span class="n">next_start_bin</span>
            <span class="n">end_bin</span> <span class="o">=</span> <span class="n">next_end_bin</span>

        <span class="n">new_min</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">+</span> <span class="n">bin_width</span> <span class="o">*</span> <span class="n">start_bin</span>
        <span class="n">new_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">+</span> <span class="n">bin_width</span> <span class="o">*</span> <span class="p">(</span><span class="n">end_bin</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">new_min</span><span class="p">,</span> <span class="n">new_max</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">ignore</span>
    <span class="k">def</span> <span class="nf">_adjust_min_max</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">combined_min</span><span class="p">,</span> <span class="n">combined_max</span><span class="p">,</span> <span class="n">upsample_rate</span><span class="p">):</span>
        <span class="c1"># type: (Tensor, Tensor, int) -&gt; Tuple[Tensor, Tensor, int, int]</span>
        <span class="c1"># We ensure that:</span>
        <span class="c1"># (combined_max - combined_min)/(downsample_rate*Nbins) = (max - min)/(upsample_rate*Nbins)</span>
        <span class="c1"># This allows us to have a common grid of resolution s, where we can align</span>
        <span class="c1"># the input histogram</span>
        <span class="c1"># start_idx maps min_val to the histogram bin index.</span>

        <span class="n">hist_bin_width</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_val</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bins</span> <span class="o">*</span> <span class="n">upsample_rate</span><span class="p">)</span>
        <span class="n">downsample_rate</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">ceil</span><span class="p">((</span><span class="n">combined_max</span> <span class="o">-</span> <span class="n">combined_min</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bins</span> <span class="o">*</span> <span class="n">hist_bin_width</span><span class="p">))</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">int</span><span class="p">)</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
        <span class="n">e</span> <span class="o">=</span> <span class="n">downsample_rate</span> <span class="o">*</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bins</span> <span class="o">*</span> <span class="n">hist_bin_width</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">combined_max</span> <span class="o">-</span> <span class="n">combined_min</span><span class="p">)</span>
        <span class="n">combined_max</span> <span class="o">=</span> <span class="n">combined_max</span> <span class="o">+</span> <span class="n">e</span> <span class="o">/</span> <span class="mi">2</span>
        <span class="n">combined_min</span> <span class="o">=</span> <span class="n">combined_min</span> <span class="o">-</span> <span class="n">e</span> <span class="o">/</span> <span class="mi">2</span>
        <span class="n">start_idx</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">round</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">-</span> <span class="n">combined_min</span><span class="p">)</span> <span class="o">/</span> <span class="n">hist_bin_width</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">int</span><span class="p">)</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">combined_min</span><span class="p">,</span> <span class="n">combined_max</span><span class="p">,</span> <span class="n">downsample_rate</span><span class="p">,</span> <span class="n">start_idx</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">ignore</span>
    <span class="k">def</span> <span class="nf">_combine_histograms</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orig_hist</span><span class="p">,</span> <span class="n">new_hist</span><span class="p">,</span> <span class="n">upsample_rate</span><span class="p">,</span> <span class="n">downsample_rate</span><span class="p">,</span> <span class="n">start_idx</span><span class="p">,</span> <span class="n">Nbins</span><span class="p">):</span>
        <span class="c1"># type: (Tensor, Tensor, int, int, int, int) -&gt; Tensor</span>
        <span class="c1"># First up-sample the histogram with new data by a factor of L</span>
        <span class="c1"># This creates an approximate probability density thats piecwise constant</span>
        <span class="n">upsampled_histogram</span> <span class="o">=</span> <span class="n">new_hist</span><span class="o">.</span><span class="n">repeat_interleave</span><span class="p">(</span><span class="n">upsample_rate</span><span class="p">)</span>
        <span class="c1"># Now insert the upsampled histogram into the output</span>
        <span class="c1"># histogram, which is initialized with zeros.</span>
        <span class="c1"># The offset at which the histogram is introduced is determined</span>
        <span class="c1"># by the start index as the output histogram can cover a wider range</span>
        <span class="n">histogram_with_output_range</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">Nbins</span> <span class="o">*</span> <span class="n">downsample_rate</span><span class="p">),</span> <span class="n">device</span><span class="o">=</span><span class="n">orig_hist</span><span class="o">.</span><span class="n">device</span><span class="p">)</span>
        <span class="n">histogram_with_output_range</span><span class="p">[</span><span class="n">start_idx</span><span class="p">:</span><span class="n">Nbins</span> <span class="o">*</span> <span class="n">upsample_rate</span> <span class="o">+</span> <span class="n">start_idx</span><span class="p">]</span> <span class="o">=</span> <span class="n">upsampled_histogram</span>
        <span class="c1"># Compute integral histogram, double precision is needed to ensure</span>
        <span class="c1"># that there are no overflows</span>
        <span class="n">integral_histogram</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">histogram_with_output_range</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
                                          <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">double</span><span class="p">)[</span><span class="n">downsample_rate</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">::</span> <span class="n">downsample_rate</span><span class="p">]</span>
        <span class="c1"># Finally perform interpolation</span>
        <span class="n">shifted_integral_histogram</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">Nbins</span><span class="p">),</span> <span class="n">device</span><span class="o">=</span><span class="n">orig_hist</span><span class="o">.</span><span class="n">device</span><span class="p">)</span>
        <span class="n">shifted_integral_histogram</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="n">Nbins</span><span class="p">]</span> <span class="o">=</span> <span class="n">integral_histogram</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">interpolated_histogram</span> <span class="o">=</span> <span class="p">(</span><span class="n">integral_histogram</span> <span class="o">-</span> <span class="n">shifted_integral_histogram</span><span class="p">)</span> <span class="o">/</span> <span class="n">upsample_rate</span>
        <span class="n">orig_hist</span> <span class="o">=</span> <span class="n">orig_hist</span> <span class="o">+</span> <span class="n">interpolated_histogram</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">orig_hist</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_orig</span><span class="p">):</span>
        <span class="c1"># type: (Tensor) -&gt; Tensor</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">x_orig</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>
        <span class="n">min_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span>
        <span class="n">max_val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span>
        <span class="k">if</span> <span class="n">min_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">max_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">min_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">max_val</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">=</span> <span class="n">min_val</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span> <span class="o">=</span> <span class="n">max_val</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">histogram</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">histc</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span><span class="p">,</span> <span class="nb">min</span><span class="o">=</span><span class="n">min_val</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="n">max_val</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">new_min</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">new_max</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
            <span class="n">combined_min</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">new_min</span><span class="p">,</span> <span class="n">min_val</span><span class="p">)</span>
            <span class="n">combined_max</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">new_max</span><span class="p">,</span> <span class="n">max_val</span><span class="p">)</span>
            <span class="c1"># combine the existing histogram and new histogram into 1 histogram</span>
            <span class="c1"># We do this by first upsampling the histogram to a dense grid</span>
            <span class="c1"># and then downsampling the histogram efficiently</span>
            <span class="n">combined_min</span><span class="p">,</span> <span class="n">combined_max</span><span class="p">,</span> <span class="n">downsample_rate</span><span class="p">,</span> <span class="n">start_idx</span> <span class="o">=</span> \
                <span class="bp">self</span><span class="o">.</span><span class="n">_adjust_min_max</span><span class="p">(</span><span class="n">combined_min</span><span class="p">,</span> <span class="n">combined_max</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">upsample_rate</span><span class="p">)</span>
            <span class="n">combined_histogram</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">histc</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span><span class="p">,</span> <span class="nb">min</span><span class="o">=</span><span class="n">combined_min</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="n">combined_max</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">combined_min</span> <span class="o">==</span> <span class="n">min_val</span> <span class="ow">and</span> <span class="n">combined_max</span> <span class="o">==</span> <span class="n">max_val</span><span class="p">:</span>
                <span class="n">combined_histogram</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">histogram</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">combined_histogram</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_combine_histograms</span><span class="p">(</span>
                    <span class="n">combined_histogram</span><span class="p">,</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">histogram</span><span class="p">,</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">upsample_rate</span><span class="p">,</span>
                    <span class="n">downsample_rate</span><span class="p">,</span>
                    <span class="n">start_idx</span><span class="p">,</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">bins</span><span class="p">)</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">histogram</span> <span class="o">=</span> <span class="n">combined_histogram</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span> <span class="o">=</span> <span class="n">combined_min</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span> <span class="o">=</span> <span class="n">combined_max</span>
        <span class="k">return</span> <span class="n">x_orig</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">warnings</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span>
                <span class="s2">&quot;must run observer before calling calculate_qparams.</span><span class="se">\</span>
<span class="s2">                                    Returning default scale and zero point &quot;</span>
            <span class="p">)</span>
            <span class="k">return</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mf">1.0</span><span class="p">]),</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="mi">0</span><span class="p">])</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">bins</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">histogram</span><span class="p">),</span> <span class="p">(</span>
            <span class="s2">&quot;The number of bins in histogram should be equal to the number of bins &quot;</span>
            <span class="s2">&quot;supplied while making this observer&quot;</span>
        <span class="p">)</span>

        <span class="n">new_min</span><span class="p">,</span> <span class="n">new_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_non_linear_param_search</span><span class="p">()</span>

        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calculate_qparams</span><span class="p">(</span><span class="n">new_min</span><span class="p">,</span> <span class="n">new_max</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">_save_to_state_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">keep_vars</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">HistogramObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_save_to_state_dict</span><span class="p">(</span><span class="n">destination</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">keep_vars</span><span class="p">)</span>
        <span class="n">destination</span><span class="p">[</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">&#39;min_val&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_val</span>
        <span class="n">destination</span><span class="p">[</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">&#39;max_val&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_val</span>

    <span class="k">def</span> <span class="nf">_load_from_state_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state_dict</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">local_metadata</span><span class="p">,</span> <span class="n">strict</span><span class="p">,</span>
                              <span class="n">missing_keys</span><span class="p">,</span> <span class="n">unexpected_keys</span><span class="p">,</span> <span class="n">error_msgs</span><span class="p">):</span>

        <span class="n">local_state</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;min_val&#39;</span><span class="p">,</span> <span class="s1">&#39;max_val&#39;</span><span class="p">]</span>
        <span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">local_state</span><span class="p">:</span>
            <span class="n">key</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="n">name</span>
            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">state_dict</span><span class="p">:</span>
                <span class="n">val</span> <span class="o">=</span> <span class="n">state_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
                <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span>
            <span class="k">elif</span> <span class="n">strict</span><span class="p">:</span>
                <span class="n">missing_keys</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">HistogramObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_load_from_state_dict</span><span class="p">(</span><span class="n">state_dict</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">local_metadata</span><span class="p">,</span> <span class="n">strict</span><span class="p">,</span>
                                                             <span class="n">missing_keys</span><span class="p">,</span> <span class="n">unexpected_keys</span><span class="p">,</span> <span class="n">error_msgs</span><span class="p">)</span></div>

<div class="viewcode-block" id="RecordingObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.RecordingObserver">[docs]</a><span class="k">class</span> <span class="nc">RecordingObserver</span><span class="p">(</span><span class="n">_ObserverBase</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    The module is mainly for debug and records the tensor values during runtime.</span>

<span class="sd">    Args:</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">        qscheme: Quantization scheme to be used</span>
<span class="sd">        reduce_range: Reduces the range of the quantized data type by 1 bit</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="vm">__annotations__</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;tensor_val&quot;</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Optional</span><span class="p">[</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">]]}</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">RecordingObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tensor_val</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tensor_val</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">clone</span><span class="p">())</span>
        <span class="k">return</span> <span class="n">x</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">&quot;calculate_qparams should not be called for RecordingObserver&quot;</span><span class="p">)</span>

    <span class="nd">@torch</span><span class="o">.</span><span class="n">jit</span><span class="o">.</span><span class="n">export</span>
    <span class="k">def</span> <span class="nf">get_tensor_value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">tensor_val</span></div>


<div class="viewcode-block" id="NoopObserver"><a class="viewcode-back" href="../../../quantization.html#torch.quantization.NoopObserver">[docs]</a><span class="k">class</span> <span class="nc">NoopObserver</span><span class="p">(</span><span class="n">ObserverBase</span><span class="p">):</span>
    <span class="sa">r</span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Observer that doesn&#39;t do anything and just passes its configuration to the</span>
<span class="sd">    quantized module&#39;s ``.from_float()``.</span>

<span class="sd">    Primarily used for quantization to float16 which doesn&#39;t require determining</span>
<span class="sd">    ranges.</span>

<span class="sd">    Args:</span>
<span class="sd">        dtype: Quantized data type</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float16</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">dtype</span> <span class="o">!=</span> <span class="n">torch</span><span class="o">.</span><span class="n">float16</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Only float16 quantization can be used without calibration process&quot;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">NoopObserver</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">dtype</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">x</span>

    <span class="k">def</span> <span class="nf">calculate_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">&quot;calculate_qparams should not be called for NoopObserver&quot;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_qparams</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">calculate_qparams</span><span class="p">()</span></div>


<span class="c1"># Restrict activations to be in the range (0,127)</span>
<span class="n">default_observer</span> <span class="o">=</span> <span class="n">MinMaxObserver</span><span class="o">.</span><span class="n">with_args</span><span class="p">(</span><span class="n">reduce_range</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">default_debug_observer</span> <span class="o">=</span> <span class="n">RecordingObserver</span>
<span class="n">default_weight_observer</span> <span class="o">=</span> <span class="n">MinMaxObserver</span><span class="o">.</span><span class="n">with_args</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">qint8</span><span class="p">,</span> <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_tensor_symmetric</span><span class="p">)</span>
<span class="n">default_histogram_observer</span> <span class="o">=</span> <span class="n">HistogramObserver</span><span class="o">.</span><span class="n">with_args</span><span class="p">(</span><span class="n">reduce_range</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">default_per_channel_weight_observer</span> <span class="o">=</span> <span class="n">PerChannelMinMaxObserver</span><span class="o">.</span><span class="n">with_args</span><span class="p">(</span><span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">qint8</span><span class="p">,</span> <span class="n">qscheme</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">per_channel_symmetric</span><span class="p">)</span>
</pre></div>

             </article>
             
            </div>
            <footer>
  

  

    <hr>

  

  <div role="contentinfo">
    <p>
        &copy; Copyright 2019, Torch Contributors.

    </p>
  </div>
    
      <div>
        Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
      </div>
     

</footer>

          </div>
        </div>

        <div class="pytorch-content-right" id="pytorch-content-right">
          <div class="pytorch-right-menu" id="pytorch-right-menu">
            <div class="pytorch-side-scroll" id="pytorch-side-scroll-right">
              
            </div>
          </div>
        </div>
      </section>
    </div>

  


  

     
       <script type="text/javascript" id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
         <script src="../../../_static/jquery.js"></script>
         <script src="../../../_static/underscore.js"></script>
         <script src="../../../_static/doctools.js"></script>
         <script src="../../../_static/language_data.js"></script>
     

  

  <script type="text/javascript" src="../../../_static/js/vendor/popper.min.js"></script>
  <script type="text/javascript" src="../../../_static/js/vendor/bootstrap.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>
  <script type="text/javascript" src="../../../_static/js/theme.js"></script>

  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script>
 
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-90545585-1', 'auto');
  ga('send', 'pageview');

</script>

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-117752657-2"></script>

<script>
  window.dataLayer = window.dataLayer || [];

  function gtag(){dataLayer.push(arguments);}

  gtag('js', new Date());
  gtag('config', 'UA-117752657-2');
</script>

<img height="1" width="1" style="border-style:none;" alt="" src="https://www.googleadservices.com/pagead/conversion/795629140/?label=txkmCPmdtosBENSssfsC&amp;guid=ON&amp;script=0"/>


  <!-- Begin Footer -->

  <div class="container-fluid docs-tutorials-resources" id="docs-tutorials-resources">
    <div class="container">
      <div class="row">
        <div class="col-md-4 text-center">
          <h2>Docs</h2>
          <p>Access comprehensive developer documentation for PyTorch</p>
          <a class="with-right-arrow" href="https://pytorch.org/docs/stable/index.html">View Docs</a>
        </div>

        <div class="col-md-4 text-center">
          <h2>Tutorials</h2>
          <p>Get in-depth tutorials for beginners and advanced developers</p>
          <a class="with-right-arrow" href="https://pytorch.org/tutorials">View Tutorials</a>
        </div>

        <div class="col-md-4 text-center">
          <h2>Resources</h2>
          <p>Find development resources and get your questions answered</p>
          <a class="with-right-arrow" href="https://pytorch.org/resources">View Resources</a>
        </div>
      </div>
    </div>
  </div>

  <footer class="site-footer">
    <div class="container footer-container">
      <div class="footer-logo-wrapper">
        <a href="https://pytorch.org/" class="footer-logo"></a>
      </div>

      <div class="footer-links-wrapper">
        <div class="footer-links-col">
          <ul>
            <li class="list-title"><a href="https://pytorch.org/">PyTorch</a></li>
            <li><a href="https://pytorch.org/get-started">Get Started</a></li>
            <li><a href="https://pytorch.org/features">Features</a></li>
            <li><a href="https://pytorch.org/ecosystem">Ecosystem</a></li>
            <li><a href="https://pytorch.org/blog/">Blog</a></li>
            <li><a href="https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md">Contributing</a></li>
          </ul>
        </div>

        <div class="footer-links-col">
          <ul>
            <li class="list-title"><a href="https://pytorch.org/resources">Resources</a></li>
            <li><a href="https://pytorch.org/tutorials">Tutorials</a></li>
            <li><a href="https://pytorch.org/docs/stable/index.html">Docs</a></li>
            <li><a href="https://discuss.pytorch.org" target="_blank">Discuss</a></li>
            <li><a href="https://github.com/pytorch/pytorch/issues" target="_blank">Github Issues</a></li>
            <li><a href="https://pytorch.org/assets/brand-guidelines/PyTorch-Brand-Guidelines.pdf" target="_blank">Brand Guidelines</a></li>
          </ul>
        </div>

        <div class="footer-links-col follow-us-col">
          <ul>
            <li class="list-title">Stay Connected</li>
            <li>
              <div id="mc_embed_signup">
                <form
                  action="https://twitter.us14.list-manage.com/subscribe/post?u=75419c71fe0a935e53dfa4a3f&id=91d0dccd39"
                  method="post"
                  id="mc-embedded-subscribe-form"
                  name="mc-embedded-subscribe-form"
                  class="email-subscribe-form validate"
                  target="_blank"
                  novalidate>
                  <div id="mc_embed_signup_scroll" class="email-subscribe-form-fields-wrapper">
                    <div class="mc-field-group">
                      <label for="mce-EMAIL" style="display:none;">Email Address</label>
                      <input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL" placeholder="Email Address">
                    </div>

                    <div id="mce-responses" class="clear">
                      <div class="response" id="mce-error-response" style="display:none"></div>
                      <div class="response" id="mce-success-response" style="display:none"></div>
                    </div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->

                    <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_75419c71fe0a935e53dfa4a3f_91d0dccd39" tabindex="-1" value=""></div>

                    <div class="clear">
                      <input type="submit" value="" name="subscribe" id="mc-embedded-subscribe" class="button email-subscribe-button">
                    </div>
                  </div>
                </form>
              </div>

            </li>
          </ul>

          <div class="footer-social-icons">
            <a href="https://www.facebook.com/pytorch" target="_blank" class="facebook"></a>
            <a href="https://twitter.com/pytorch" target="_blank" class="twitter"></a>
            <a href="https://www.youtube.com/pytorch" target="_blank" class="youtube"></a>
          </div>
        </div>
      </div>
    </div>
  </footer>

  <div class="cookie-banner-wrapper">
  <div class="container">
    <p class="gdpr-notice">To analyze traffic and optimize your experience, we serve cookies on this site. By clicking or navigating, you agree to allow our usage of cookies. As the current maintainers of this site, Facebook’s Cookies Policy applies. Learn more, including about available controls: <a href="https://www.facebook.com/policies/cookies/">Cookies Policy</a>.</p>
    <img class="close-button" src="../../../_static/images/pytorch-x.svg">
  </div>
</div>

  <!-- End Footer -->

  <!-- Begin Mobile Menu -->

  <div class="mobile-main-menu">
    <div class="container-fluid">
      <div class="container">
        <div class="mobile-main-menu-header-container">
          <a class="header-logo" href="https://pytorch.org/" aria-label="PyTorch"></a>
          <a class="main-menu-close-button" href="#" data-behavior="close-mobile-menu"></a>
        </div>
      </div>
    </div>

    <div class="mobile-main-menu-links-container">
      <div class="main-menu">
        <ul>
          <li>
            <a href="https://pytorch.org/get-started">Get Started</a>
          </li>

          <li>
            <a href="https://pytorch.org/features">Features</a>
          </li>

          <li>
            <a href="https://pytorch.org/ecosystem">Ecosystem</a>
          </li>

          <li>
            <a href="https://pytorch.org/mobile">Mobile</a>
          </li>

          <li>
            <a href="https://pytorch.org/hub">PyTorch Hub</a>
          </li>

          <li>
            <a href="https://pytorch.org/blog/">Blog</a>
          </li>

          <li>
            <a href="https://pytorch.org/tutorials">Tutorials</a>
          </li>

          <li class="active">
            <a href="https://pytorch.org/docs/stable/index.html">Docs</a>
          </li>

          <li>
            <a href="https://pytorch.org/resources">Resources</a>
          </li>

          <li>
            <a href="https://github.com/pytorch/pytorch">Github</a>
          </li>
        </ul>
      </div>
    </div>
  </div>

  <!-- End Mobile Menu -->

  <script type="text/javascript" src="../../../_static/js/vendor/anchor.min.js"></script>

  <script type="text/javascript">
    $(document).ready(function() {
      mobileMenu.bind();
      mobileTOC.bind();
      pytorchAnchors.bind();
      sideMenus.bind();
      scrollToAnchor.bind();
      highlightNavigation.bind();
      mainMenuDropdown.bind();
      filterTags.bind();

      // Remove any empty p tags that Sphinx adds
      $("[data-tags='null']").remove();

      // Add class to links that have code blocks, since we cannot create links in code blocks
      $("article.pytorch-article a span.pre").each(function(e) {
        $(this).closest("a").addClass("has-code");
      });
    })
  </script>
</body>
</html>